﻿using System;
using System.Text;
using System.Collections.Generic;
using System.Linq;
using Microsoft.VisualStudio.TestTools.UnitTesting;
using SpeakupBackend.Themes;

namespace SpeakupTests.SpeakupBackend.Themes
{
    [TestClass]
    public class BaseLevelGroupFactoryTests
    {
        /// <summary>
        /// Passed null to base class. This should result in exception.
        /// </summary>
        class NullListLevelGroupFactory : BaseLevelGroupFactory<LevelGroup>
        {
            public NullListLevelGroupFactory()
                : base(null)
            { }

            protected override LevelGroup CreateLevelGroup(int min, int max)
            {
                PrivateObject pi = new PrivateObject(typeof(LevelGroup), min, max);
                return (LevelGroup)pi.Target;
            }
        }

        static List<Tuple<int, int>> InvalidLevelGroups = new List<Tuple<int, int>>();

        [ClassInitialize]
        public static void ClassInitialize(TestContext context)
        {
            DefaultLevelGroupFactory factory = new DefaultLevelGroupFactory();

            foreach (Tuple<int, int> tuple in factory.ValidLevelGroups)
            {
                //expanded
                InvalidLevelGroups.Add(new Tuple<int, int>(tuple.Item1, tuple.Item2 + 1));
                InvalidLevelGroups.Add(new Tuple<int, int>(tuple.Item1 - 1, tuple.Item2));

                //inversed
                if (tuple.Item1 != tuple.Item2)
                {
                    InvalidLevelGroups.Add(new Tuple<int, int>(tuple.Item2, tuple.Item1));
                }

                //invalid level number
                InvalidLevelGroups.Add(new Tuple<int, int>(Level.MinValidLevelNumber - 1, tuple.Item2));
                InvalidLevelGroups.Add(new Tuple<int, int>(tuple.Item1, Level.MaxValidLevelNumber + 1));
            }
        }

        DefaultLevelGroupFactory LevelGroupFactory;

        [TestInitialize]
        public void TestInitialize()
        {
            LevelGroupFactory = new DefaultLevelGroupFactory();
        }

        

        [TestMethod]
        public void NullList2Ctor()
        {
            bool thrown = false;
            try
            {
                new NullListLevelGroupFactory();
            }
            catch (ArgumentException)
            {
                thrown = true;
            }

            Assert.IsTrue(thrown);
        }

        [TestMethod]
        public void IsLevelGroupValid()
        {
            //confirm all valid values are recognized as valid
            foreach (var tuple in LevelGroupFactory.ValidLevelGroups)
            {
                Assert.IsTrue(LevelGroupFactory.IsValidLevelGroup(tuple.Item1, tuple.Item2));
            }

            //confirm all invalid values are recognized as invalid
            foreach (var tuple in InvalidLevelGroups)
            {
                Assert.IsFalse(LevelGroupFactory.IsValidLevelGroup(tuple.Item1, tuple.Item2));
            }
        }

        [TestMethod]
        public void GetLevelGroups()
        {
            IList<LevelGroup> levelGroups = LevelGroupFactory.GetLevelGroups();
            IList<Tuple<int, int>> levelGroupTuples = LevelGroupFactory.ValidLevelGroups;


            //verify that number of elements is correct
            Assert.AreEqual(levelGroups.Count, levelGroupTuples.Count);

            foreach (var tuple in levelGroupTuples)
            {
                int count = (from n in levelGroups
                             where n.MinLevel == tuple.Item1 && n.MaxLevel == tuple.Item2
                             select n).Count();

                //expect exactly 1 found item
                Assert.AreEqual(count, 1);
            }
        }

        [TestMethod]
        public void GetLevelGroupByLevelNumber()
        {
            //verify that valid levelGroups can be obtained
            for (int i = Level.MinValidLevelNumber; i <= Level.MaxValidLevelNumber; i++)
            {
                LevelGroup w =LevelGroupFactory.GetLevelGroup(i);
                Assert.IsTrue(w.MinLevel <= i && i <= w.MaxLevel);
            }

            //verify that invalid levelGroups can not be obtained
            for (int i = Level.MinValidLevelNumber - 10; i < Level.MinValidLevelNumber; i++)
            {
                bool thrown = false;
                try
                {
                   LevelGroupFactory.GetLevelGroup(i);
                }
                catch (ArgumentException)
                {
                    thrown = true;
                }

                Assert.AreEqual(true, thrown);
            }

            for (int i = Level.MaxValidLevelNumber + 10; i > Level.MaxValidLevelNumber; i--)
            {
                bool thrown = false;
                try
                {
                   LevelGroupFactory.GetLevelGroup(i);
                }
                catch (ArgumentException)
                {
                    thrown = true;
                }

                Assert.AreEqual(true, thrown);
            }
        }

        [TestMethod]
        public void GetLevelGroupByLevel()
        {
            //verify that valid levelGroups can be obtained
            for (int i = Level.MinValidLevelNumber; i <= Level.MaxValidLevelNumber; i++)
            {
                Level level = Level.GetLevel(i);
                LevelGroup w =LevelGroupFactory.GetLevelGroup(level);
                Assert.IsTrue(w.MinLevel <= level.LevelNumber && level.LevelNumber <= w.MaxLevel);
            }
        }


        [TestMethod]
        public void GetLevelGroupByString()
        {
            //verify that valid levelGroups can be obtained
            foreach (LevelGroup levelGroup in LevelGroupFactory.GetLevelGroups())
            {
                LevelGroup w =LevelGroupFactory.GetLevelGroup(levelGroup.ToString());
                Assert.AreEqual(levelGroup.MinLevel, w.MinLevel);
                Assert.AreEqual(levelGroup.MaxLevel, w.MaxLevel);
            }

            //verify that invalid levelGroups can not be obtained
            foreach (var invalidTuples in InvalidLevelGroups)
            {
                bool thrown = false;
                try
                {
                    String strLevelGroup = String.Format("{0}-{1}", invalidTuples.Item1, invalidTuples.Item2);
                   LevelGroupFactory.GetLevelGroup(strLevelGroup);
                }
                catch (ArgumentException)
                {
                    thrown = true;
                }

                Assert.AreEqual(true, thrown);
            }
        }

        [TestMethod]
        public void GetLevelGroupByInvalidString()
        {
            Random rnd = new Random();

            List<String> invalidStrings = new List<string>();

            invalidStrings.Add("3.4");
            invalidStrings.Add("3-4-6");
            invalidStrings.Add("-3-4");
            invalidStrings.Add("3+4");
            invalidStrings.Add("-");
            invalidStrings.Add("");

            foreach (var str in invalidStrings)
            {
                bool thrown = false;
                try
                {
                   LevelGroupFactory.GetLevelGroup(str);
                }
                catch (FormatException)
                {
                    thrown = true;
                }

                Assert.AreEqual(true, thrown);
            }
        }


    }
}
